{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"sk-pQ7\"\n",
    "os.environ[\"OPENAI_PROXY\"] = \"https://ai-yyds.com/v1\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "您好！我是一个由 OpenAI 创建的人工智能助手，被称作 ChatGPT。我的设计初衷是为了帮助解答问题、提供信息、进行对话以及在多种情况下协助人类。我的知识库大约在 2023 年初截止，这意味着我在那之后发生的事件和信息可能不了解。\n",
      "\n",
      "我可以在各种主题上进行讨论，例如科学、文化、娱乐、技术等等。我还具备语言处理能力，可以与您进行流畅的交谈。我被编程用以遵守伦理指导原则，并致力于提供有用且中立的答案。\n",
      "\n",
      "如果您有问题或者需要帮助，请随时告诉我，我将尽我的最大努力协助您。\n"
     ]
    }
   ],
   "source": [
    "#使用openai的官方sdk\n",
    "import openai\n",
    "import os\n",
    "\n",
    "openai.api_base = os.getenv(\"OPENAI_PROXY\")\n",
    "openai.api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "\n",
    "messages = [\n",
    "{\"role\": \"user\", \"content\": \"介绍下你自己\"}\n",
    "]\n",
    "\n",
    "res = openai.ChatCompletion.create(\n",
    "model=\"gpt-4-1106-preview\",\n",
    "messages=messages,\n",
    "stream=False,\n",
    ")\n",
    "\n",
    "print(res['choices'][0]['message']['content'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### PromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'你是一个算命大师,帮我起1个具有法国特色的女孩名字'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#字符模板\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "prompt = PromptTemplate.from_template(\"你是一个{name},帮我起1个具有{county}特色的{sex}名字\")\n",
    "prompt.format(name=\"算命大师\",county=\"法国\",sex=\"女孩\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### ChatPromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[SystemMessage(content='你是一个起名大师. 你的名字叫陈大师.', additional_kwargs={}),\n",
       " HumanMessage(content='你好陈大师,你感觉如何？', additional_kwargs={}, example=False),\n",
       " AIMessage(content='你好！我状态非常好!', additional_kwargs={}, example=False),\n",
       " HumanMessage(content='你叫什么名字呢?', additional_kwargs={}, example=False),\n",
       " AIMessage(content='你好！我叫陈大师', additional_kwargs={}, example=False),\n",
       " HumanMessage(content='你的爸爸是谁呢?', additional_kwargs={}, example=False)]"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对话模板具有结构，chatmodels\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "\n",
    "chat_template = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        (\"system\", \"你是一个起名大师. 你的名字叫{name}.\"),\n",
    "        (\"human\", \"你好{name},你感觉如何？\"),\n",
    "        (\"ai\", \"你好！我状态非常好!\"),\n",
    "        (\"human\", \"你叫什么名字呢?\"),\n",
    "        (\"ai\", \"你好！我叫{name}\"),\n",
    "        (\"human\", \"{user_input}\"),\n",
    "    ]\n",
    ")\n",
    "\n",
    "chat_template.format_messages(name=\"陈大师\", user_input=\"你的爸爸是谁呢?\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<code>\n",
    "[\n",
    "    SystemMessage(content='你是一个起名大师. 你的名字叫陈大师.'), \n",
    "    HumanMessage(content='你好陈大师,你感觉如何？'), \n",
    "    AIMessage(content='你好！我状态非常好!'), \n",
    "    HumanMessage(content='你叫什么名字呢?')\n",
    "]\n",
    "</code>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[SystemMessage(content='你是一个起名大师', additional_kwargs={'大师姓名': '陈瞎子'}),\n",
       " HumanMessage(content='请问大师叫什么?', additional_kwargs={}, example=False),\n",
       " AIMessage(content='我叫陈瞎子', additional_kwargs={}, example=False)]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "from langchain.schema import SystemMessage\n",
    "from langchain.schema import HumanMessage\n",
    "from langchain.schema import AIMessage\n",
    "\n",
    "# 直接创建消息\n",
    "sy = SystemMessage(\n",
    "  content=\"你是一个起名大师\",\n",
    "  additional_kwargs={\"大师姓名\": \"陈瞎子\"}\n",
    ")\n",
    "\n",
    "hu = HumanMessage(\n",
    "  content=\"请问大师叫什么?\"\n",
    ")\n",
    "ai = AIMessage(\n",
    "  content=\"我叫陈瞎子\"\n",
    ")\n",
    "[sy,hu,ai]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "ChatMessagePromptTemplate "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "ChatMessage(content='愿原力与你同在！', additional_kwargs={}, role='天行者')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "from langchain.prompts import AIMessagePromptTemplate\n",
    "from langchain.prompts import SystemMessagePromptTemplate\n",
    "from langchain.prompts import HumanMessagePromptTemplate\n",
    "from langchain.prompts import ChatMessagePromptTemplate\n",
    "\n",
    "prompt = \"愿{subject}与你同在！\"\n",
    "\n",
    "chat_message_prompt = ChatMessagePromptTemplate.from_template(role=\"天行者\",template=prompt)\n",
    "chat_message_prompt.format(subject=\"原力\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### 自定义模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你是一个非常有经验和天赋的程序员，现在给你如下函数名称，你会按照如下格式，输出这段代码的名称、源代码、中文解释。\n",
      "函数名称: hello_world\n",
      "源代码:\n",
      "def hello_world(abc):\n",
      "    print(\"Hello, world!\")\n",
      "    return abc\n",
      "\n",
      "代码解释:\n",
      "\n",
      "函数名称: hello_world\n",
      "源代码:\n",
      "def hello_world(abc):\n",
      "    print(\"Hello, world!\")\n",
      "    return abc\n",
      "\n",
      "代码解释:\n",
      "这是一个名为hello_world的函数，它接受一个参数abc，并打印出\"Hello, world!\"，最后返回参数abc。它的作用是打印出\"Hello, world!\"这句话，并将参数abc返回。\n"
     ]
    }
   ],
   "source": [
    "\n",
    "##函数大师：根据函数名称，查找函数代码，并给出中文的代码说明\n",
    "\n",
    "from langchain.prompts import StringPromptTemplate\n",
    "\n",
    "\n",
    "# 定义一个简单的函数作为示例效果\n",
    "def hello_world(abc):\n",
    "    print(\"Hello, world!\")\n",
    "    return abc\n",
    "\n",
    "\n",
    "PROMPT = \"\"\"\\\n",
    "你是一个非常有经验和天赋的程序员，现在给你如下函数名称，你会按照如下格式，输出这段代码的名称、源代码、中文解释。\n",
    "函数名称: {function_name}\n",
    "源代码:\n",
    "{source_code}\n",
    "代码解释:\n",
    "\"\"\"\n",
    "\n",
    "import inspect\n",
    "\n",
    "\n",
    "def get_source_code(function_name):\n",
    "    #获得源代码\n",
    "    return inspect.getsource(function_name)\n",
    "\n",
    "#自定义的模板class\n",
    "class CustmPrompt(StringPromptTemplate):\n",
    "\n",
    "    \n",
    "    def format(self, **kwargs) -> str:\n",
    "        # 获得源代码\n",
    "        source_code = get_source_code(kwargs[\"function_name\"])\n",
    "\n",
    "        # 生成提示词模板\n",
    "        prompt = PROMPT.format(\n",
    "            function_name=kwargs[\"function_name\"].__name__, source_code=source_code\n",
    "        )\n",
    "        return prompt\n",
    "\n",
    "a = CustmPrompt(input_variables=[\"function_name\"])\n",
    "pm = a.format(function_name=hello_world)\n",
    "\n",
    "print(pm)\n",
    "\n",
    "#和LLM连接起来\n",
    "from langchain.llms import OpenAI\n",
    "import os\n",
    "api_base = os.getenv(\"OPENAI_PROXY\")\n",
    "api_key = os.getenv(\"OPENAI_API_KEY\")\n",
    "\n",
    "llm = OpenAI(\n",
    "    model=\"gpt-3.5-turbo-instruct\",\n",
    "    temperature=0,\n",
    "    openai_api_key=api_key,\n",
    "    openai_api_base=api_base\n",
    "    )\n",
    "msg = llm.predict(pm)\n",
    "print(msg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 使用jinji2与f-string来实现提示词模板格式化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n给我讲一个关于翠花的悲伤故事\\n'"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "##f-string是python内置的一种模板引擎\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "fstring_template = \"\"\"\n",
    "给我讲一个关于{name}的{what}故事\n",
    "\"\"\"\n",
    "\n",
    "prompt = PromptTemplate.from_template(fstring_template)\n",
    "\n",
    "prompt.format(name=\"翠花\", what=\"悲伤\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "! pip install jinja2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'给我讲一个关于狗剩的高兴故事'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "##Jinja2是一个灵活、高效的Python模板引擎，可以方便地生成各种标记格式的文档。\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "jinja2_template = \"给我讲一个关于{{name}}的{{what}}故事\"\n",
    "prompt = PromptTemplate.from_template(jinja2_template, template_format=\"jinja2\")\n",
    "\n",
    "prompt.format(name=\"狗剩\", what=\"高兴\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 组合式提示词模板\n",
    "\n",
    "- Final prompt: 最终返回的提示词模板\n",
    "- Pipeline prompts：组成提示词管道的模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts.pipeline import PipelinePromptTemplate\n",
    "from langchain.prompts.prompt import PromptTemplate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 三层提示词设计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Final Prompt由一系列变量构成\n",
    "full_template = \"\"\"{Character}\n",
    "{behavior}\n",
    "{prohibit}\"\"\"\n",
    "full_prompt = PromptTemplate.from_template(full_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 第一层基本性格设计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "Character_template = \"\"\"你是{person}，你有着{xingge}.\"\"\"\n",
    "Character_prompt = PromptTemplate.from_template(Character_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 第二层行为设计"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "behavior_template = \"\"\"你遵从以下的行为:\n",
    "{behavior_list}\n",
    "\"\"\"\n",
    "behavior_prompt = PromptTemplate.from_template(behavior_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 第三层不允许的行为"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "prohibit_template = \"\"\"你不允许有以下行为:\n",
    "{prohibit_list}\n",
    "\"\"\"\n",
    "prohibit_prompt = PromptTemplate.from_template(prohibit_template)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 将三层提示词组合起来"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "input_prompts = [\n",
    "    (\"Character\", Character_prompt),\n",
    "    (\"behavior\", behavior_prompt),\n",
    "    (\"prohibit\", prohibit_prompt)\n",
    "]\n",
    "pipeline_prompt = PipelinePromptTemplate(final_prompt=full_prompt, pipeline_prompts=input_prompts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 打印下组合后模板里的可传递参数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['prohibit_list', 'person', 'xingge', 'behavior_list']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pipeline_prompt.input_variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 调用组合后的提示词模板"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "你是埃隆马斯克，你有着钢铁般的意志，你是世界首富，精通物理、天文、商业，你是商业奇才，你的终极梦想是殖民火星..\n",
      "你遵从以下的行为:\n",
      "1.你喜欢冒险 \n",
      " 2.你非常崇拜爱因斯坦 \n",
      " 3.你总是乐于助人，回答用户各种问题.\n",
      "\n",
      "你不允许有以下行为:\n",
      "1.你不可以说自己是一个人工智能助手或者机器人 \n",
      " 2.当你不知道答案的时候，可以说让我再想想. \n",
      "\n"
     ]
    }
   ],
   "source": [
    "pm = pipeline_prompt.format(\n",
    "    person=\"埃隆马斯克\",\n",
    "    xingge=\"钢铁般的意志，你是世界首富，精通物理、天文、商业，你是商业奇才，你的终极梦想是殖民火星.\",\n",
    "    behavior_list=\"1.你喜欢冒险 \\n 2.你非常崇拜爱因斯坦 \\n 3.你总是乐于助人，回答用户各种问题.\",\n",
    "    prohibit_list=\"1.你不可以说自己是一个人工智能助手或者机器人 \\n 2.当你不知道答案的时候，可以说让我再想想. \"\n",
    ")\n",
    "print(pm)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 序列化：使用文件来管理提示词模板\n",
    "\n",
    "- 便于共享\n",
    "- 便于版本管理\n",
    "- 便于存储\n",
    "- 支持常见格式(json/yaml/txt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import load_prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给我讲一个关于小黑的恐怖的故事\n"
     ]
    }
   ],
   "source": [
    "#加载yaml格式的prompt模版\n",
    "prompt = load_prompt(\"simple_prompt.yaml\")\n",
    "print(prompt.format(name=\"小黑\",what=\"恐怖的\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "给我讲一个关于小红的搞笑的故事\n"
     ]
    }
   ],
   "source": [
    "#加载json格式的prompt模版\n",
    "prompt = load_prompt(\"simple_prompt.json\")\n",
    "print(prompt.format(name=\"小红\",what=\"搞笑的\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'answer': 'George Washington was born in 1732 and died in 1799.',\n",
       " 'score': '1/2'}"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#支持加载文件格式的模版，并且对prompt的最终解析结果进行自定义格式化\n",
    "prompt = load_prompt(\"prompt_with_output_parser.json\")\n",
    "prompt.output_parser.parse(\n",
    "    \"George Washington was born in 1732 and died in 1799.\\nScore: 1/2\"\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchains",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
    